package com.cn.yds.bdy.service.ipml;

import com.cn.yds.bdy.dao.DictionaryRepository;
import com.cn.yds.bdy.dao.OptRepository;
import com.cn.yds.bdy.dao.TopicRepository;
import com.cn.yds.bdy.dao.model.DictionaryModel;
import com.cn.yds.bdy.dao.model.Topic;
import com.cn.yds.bdy.dao.model.TopicModel;
import com.cn.yds.bdy.dao.model.TopicPo;
import com.cn.yds.bdy.dao.model.UserModel;
import com.cn.yds.bdy.enums.TopicStatusEnum;
import com.cn.yds.bdy.service.TopicService;
import com.cn.yds.bdy.utils.ComentUtils;
import com.cn.yds.bdy.vo.SearchParamVo;
import com.cn.yds.bdy.vo.StudentVo;
import com.cn.yds.bdy.vo.TopicCollectVo;
import com.cn.yds.bdy.vo.TypeCensusVo;
import com.cn.yds.bdy.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

@Slf4j
@Service
public class TopicServiceImpl implements TopicService {

    @Autowired
    private TopicRepository topicRepository;
    @Autowired
    private OptRepository optRepository;
    @Autowired
    private DictionaryRepository dictionaryRepository;

    @Override
    public TopicCollectVo collectTeachersTopic(Integer teacherId) {
        TopicCollectVo topicCollectVo = new TopicCollectVo();
        List<TopicModel> topicModels = topicRepository.findByTeacherId(teacherId);
        // 1.group by month
        Map<Integer, Long> collectByMonth = topicModels.stream().collect(
                Collectors.groupingBy(k -> ComentUtils.getMonth(k.getCreateTime()),Collectors.counting()));
        List<Integer> allMonths = Stream.iterate(1, n -> n + 1).limit(12).collect(Collectors.toList());
        collectByMonth = setDefaultValue(allMonths,collectByMonth);
        List<Long> collectByMonthList = collectByMonth.entrySet().stream().map(k -> k.getValue()).collect(Collectors.toList());

        // 2.group by type
        Map<Integer, Long> collectByType = topicModels.stream().collect(Collectors.groupingBy(TopicModel::getType, Collectors.counting()));
        // topic type is 1
        List<DictionaryModel> topicType = dictionaryRepository.findByType(1);
        List<Integer> allTypes = topicType.stream().map(DictionaryModel::getId).collect(Collectors.toList());
        collectByType = setDefaultValue(allTypes,collectByType);
        List<TypeCensusVo> collectByTypeList = collectByType.entrySet().stream().map(k -> {
            DictionaryModel dictionaryModel = topicType.stream().filter(j -> j.getId().equals(k.getKey())).findFirst().orElse(null);
            TypeCensusVo typeCensusVo = new TypeCensusVo();
            if (Objects.nonNull(dictionaryModel)) {
                typeCensusVo.setName(dictionaryModel.getValue());
                typeCensusVo.setNum(k.getValue().intValue());
            }
            return typeCensusVo;
        }).sorted(Comparator.comparing(TypeCensusVo::getNum).reversed()).collect(Collectors.toList());
        topicCollectVo.setMonth(collectByMonthList);
        topicCollectVo.setType(collectByTypeList);
        return topicCollectVo;
    }

    private  Map<Integer, Long>  setDefaultValue(List<Integer> allUnit, Map<Integer, Long> collectByMonth) {

        for (Integer unit : allUnit) {
            boolean b = collectByMonth.entrySet().stream().noneMatch(k -> k.getKey().equals(unit));
            if(b){
                collectByMonth.put(unit, (long) 0);
            }
        }
        return collectByMonth;
    }

    @Override
    public TopicPo findById(Integer topicId) {
        return topicRepository.findTopicPoById(topicId);

    }

    @Override
    public Integer updateTopic(TopicModel topicModel) {
        TopicModel saveOrUpdateTopic =null;
        if(Objects.isNull(topicModel.getId())){
            topicModel.setStatus(TopicStatusEnum.NEW.getStatus());
            saveOrUpdateTopic = topicModel;

        }else{
            TopicModel originTopic = topicRepository.findById(topicModel.getId()).orElse(null);
            if(Objects.nonNull(originTopic)){
                originTopic.setStatus(topicModel.getStatus());
                originTopic.setTopicName(topicModel.getTopicName());
                originTopic.setDescription(topicModel.getDescription());
            }
            saveOrUpdateTopic = originTopic;
        }
        topicRepository.save(saveOrUpdateTopic);
        return 1;
    }

    @Override
    public Page<Topic> findTopics(SearchParamVo searchParam) {

        ComentUtils.isTrueExecute(searchParam.getStatus() == -1, () -> searchParam.setStatus(null));
        ComentUtils.isTrueExecute(StringUtils.isEmpty(searchParam.getText()), () -> searchParam.setText(""));

        // Role: 1 is student, 0 is teacher
        List<Integer> status = new ArrayList<>();
        ComentUtils.isTrueExecute(searchParam.getRole() == 1, () -> status.add(TopicStatusEnum.SELETING.getStatus()));
        ComentUtils.isTrueExecute(searchParam.getRole() == 0 && Objects.isNull(searchParam.getStatus()),
                () -> status.addAll(TopicStatusEnum.getValues()));
        ComentUtils.isTrueExecute(searchParam.getRole() == 0 && Objects.nonNull(searchParam.getStatus()),
                () -> status.add(searchParam.getStatus()));


        Pageable of = PageRequest.of(searchParam.getNum()-1, searchParam.getSize(), Sort.Direction.DESC, "createTime");

        Page<Topic> byStatus;
        if (searchParam.getRole() == 1) {
            log.info("student start select topic");
            byStatus = topicRepository.findByStatusForStudent(status, searchParam.getText(), of);
        } else {
            log.info("teacher topic manager");
            byStatus = topicRepository.findByStatus(status, searchParam.getText(), searchParam.getUserId(), of);
        }
        return byStatus;
    }


    @Override
    public List<StudentVo> getStudentsInOneTopic(Integer topicId) {
        Integer opinion = 0;
        Integer chooseStatus = 0;
        TopicModel topicModel = topicRepository.findById(topicId).orElse(null);
        Assert.notNull(topicModel,"Can't find the topic, please check.");
        if(topicModel.getStatus()==TopicStatusEnum.DONE.getStatus()){
            opinion = 1;
            chooseStatus = 1;
        }

        List<UserModel> students = optRepository.getStudentsOfTopic(topicId, opinion, chooseStatus);
        return  students.stream().map(k-> new StudentVo(k)).collect(Collectors.toList());
    }
}
